import { Addon, FunctionExt, Graph, Shape } from '@antv/x6'
import config from './config'
import { createBasicNodes, createLineNodes, createTextNodes } from './createNode'
import { register, unregister } from './shape'

export default class FlowGraph {
  // public static graph: Graph
  // private static stencil: Addon.Stencil

  static init({ container, stencil }) {
    register()
    this.graph = new Graph({
      container,
      width: 1000,
      height: 800,
      autoResize: true,
      grid: {
        size: config.size,
        visible: config.visible,
        type: config.type,
        args: [
          {
            color: config.color,
            thickness: config.thickness
          },
          {
            color: config.colorSecond,
            thickness: config.thickness,
            factor: config.factor
          }
        ]
      },
      // 画布调整
      scroller: true,
      mousewheel: {
        enabled: true,
        modifiers: ['ctrl', 'meta'],
        minScale: 0.5,
        maxScale: 2
      },
      // 画布调整
      selecting: {
        enabled: true,
        multiple: true,
        rubberband: true,
        movable: true,
        showNodeSelectionBox: true
      },
      connecting: {
        anchor: 'center',
        connectionPoint: 'boundary',
        edgeAnchor: 'orth',
        // connectionPoint: 'anchor',
        // allowMulti: 'withPort',
        allowBlank: true,
        allowEdge: true,
        highlight: true,
        snapline: true,
        createEdge() {
          return new Shape.Edge({
            attrs: {
              line: {
                stroke: config.stroke,
                strokeWidth: config.strokeWidth,
                targetMarker: {
                  name: config.targetMarkerName,
                  size: config.targetMarkerSize
                }
              }
            },
            zIndex: 0
          })
        },
        validateConnection({ sourceView, targetView, sourceMagnet, targetMagnet }) {
          if (sourceView === targetView) {
            return false
          }
          if (!sourceMagnet) {
            return false
          }
          // if (!targetMagnet) {
          //   return false
          // }
          return true
        }
      },
      // highlighting: {
      //   magnetAvailable: {
      //     name: 'stroke',
      //     args: {
      //       padding: 4,
      //       attrs: {
      //         strokeWidth: 4,
      //         stroke: 'rgba(223,234,255)'
      //       }
      //     }
      //   }
      // },
      // snapline: true,
      history: true,
      clipboard: {
        enabled: true
      },
      keyboard: {
        enabled: true
      },
      embedding: {
        enabled: true,
        findParent({ node }) {
          const bbox = node.getBBox()
          return this.getNodes().filter((node) => {
            // 只有 data.parent 为 true 的节点才是父节点
            const data = node.getData()
            if (data && data.parent) {
              const targetBBox = node.getBBox()
              return bbox.isIntersectWithRect(targetBBox)
            }
            return false
          })
        }
      }
    })
    this.initStencil(stencil)
    this.initShape()
    this.initEvent(container)
    return this.graph
  }

  static initStencil(stencilContainer) {
    this.stencil = new Addon.Stencil({
      title: 'Components',
      target: this.graph,
      stencilGraphWidth: 280,
      // search: { rect: true },
      collapsable: true,
      groups: [
        {
          name: 'basic',
          title: '基础节点',
          graphHeight: 320
        },
        {
          name: 'text',
          title: '文本',
          graphHeight: 80
        },
        {
          name: 'line',
          title: '线',
          graphHeight: 360,
          layoutOptions: {
            columns: 1
          }
        }
        // {
        //   name: 'combination',
        //   title: '组合节点',
        //   layoutOptions: {
        //     columns: 1,
        //     marginX: 60
        //   },
        //   graphHeight: 260
        // },
        // {
        //   name: 'group',
        //   title: '节点组',
        //   graphHeight: 100,
        //   layoutOptions: {
        //     columns: 1,
        //     marginX: 60
        //   }
        // }
      ]
    })
    stencilContainer.appendChild(this.stencil.container)
  }

  static initShape() {
    const { graph } = this

    // const c1 = graph.createNode({
    //   shape: 'flow-chart-image-rect'
    // })
    // const c2 = graph.createNode({
    //   shape: 'flow-chart-title-rect'
    // })
    // const c3 = graph.createNode({
    //   shape: 'flow-chart-animate-text'
    // })

    // const g1 = graph.createNode({
    //   shape: 'flowGroupNode',
    //   attrs: {
    //     text: {
    //       text: 'Group Name'
    //     }
    //   },
    //   data: {
    //     parent: true
    //   }
    // })
    const basicNodes = createBasicNodes(graph)
    const textNodes = createTextNodes(graph)
    const electricNodes = createLineNodes(graph)

    this.stencil.load(basicNodes, 'basic')
    this.stencil.load(textNodes, 'text')
    this.stencil.load(electricNodes, 'line')
    // this.stencil.load([c1, c2, c3], 'combination')
    // this.stencil.load([g1], 'group')
  }

  static showPorts(ports, show) {
    for (let i = 0, len = ports.length; i < len; i = i + 1) {
      ports[i].style.visibility = show ? 'visible' : 'hidden'
    }
  }

  static initEvent(container) {
    const { graph } = this

    graph.on('node:dblclick', ({ cell, view }) => {
      const oldText = cell.attr('text/textWrap/text')
      const elem = view.container.querySelector('.x6-edit-text')
      if (elem == null) {
        return
      }
      cell.attr('text/style/display', 'none')
      if (elem) {
        elem.style.display = ''
        elem.contentEditable = 'true'
        elem.innerText = oldText
        elem.focus()
      }
      const onBlur = () => {
        cell.attr('text/textWrap/text', elem.innerText)
        cell.attr('text/style/display', '')
        elem.style.display = 'none'
        elem.contentEditable = 'false'
      }
      elem.addEventListener('blur', () => {
        onBlur()
        elem.removeEventListener('blur', onBlur)
      })
    })

    graph.on('edge:mouseenter', ({ cell }) => {
      if (graph.isSelected(cell) && cell.isEdge()) {
        cell.addTools('vertices', 'onhover')
      }
    })
    graph.on('edge:mouseleave', ({ cell }) => {
      if (cell.hasTools('onhover')) {
        cell.removeTools()
      }
    })

    graph.on('node:collapse', ({ node, e }) => {
      e.stopPropagation()
      node.toggleCollapse()
      const collapsed = node.isCollapsed()
      const cells = node.getDescendants()
      cells.forEach((n) => {
        if (collapsed) {
          n.hide()
        } else {
          n.show()
        }
      })
    })

    graph.bindKey('delete', () => {
      const cells = graph.getSelectedCells()
      if (cells.length) {
        graph.removeCells(cells)
      }
    })

    graph.on(
      'node:mouseenter',
      FunctionExt.debounce(() => {
        const ports = container.querySelectorAll('.x6-port-body')
        this.showPorts(ports, true)
      }),
      500
    )
    graph.on('node:mouseleave', () => {
      const ports = container.querySelectorAll('.x6-port-body')
      this.showPorts(ports, false)
    })

    // graph.on('edge:mouseenter', ({ edge }) => {
    //   edge.addTools([
    //     // 'source-arrowhead',
    //     // 'target-arrowhead',
    //     {
    //       name: 'button-remove',
    //       args: {
    //         distance: -30
    //       }
    //     }
    //   ])
    // })

    // graph.on('edge:mouseleave', ({ edge }) => {
    //   edge.removeTools()
    // })

    // graph.on('selection:changed', (args) => {
    //   args.added.forEach((cell) => {
    //     if (cell.isNode()) {
    //       cell.attr('body/stroke', '#ffa940')
    //     } else {
    //       cell.attr('line/stroke', '#ffa940')
    //     }
    //   })
    //   args.removed.forEach((cell) => {
    //     if (cell.isNode()) {
    //       cell.attr('body/stroke', '#080808')
    //     } else {
    //       cell.attr('line/stroke', '#080808')
    //     }
    //   })
    // })
  }

  // 销毁
  static destroy() {
    this.graph.dispose()
    unregister()
  }
}
